#include "STC89C5xRC.H"
#include "lcd1602.h"

#define LCD1602_DATA_PORT P0  /* !> lcd1602 data port */
sbit lcd1602_rs_pin = P1 ^ 0; /* !> lcd1602 rs pin */
sbit lcd1602_rw_pin = P1 ^ 1; /* !> lcd1602 rw pin */
sbit lcd1602_en_pin = P2 ^ 5; /* !> lcd1602 en pin */

/**
 * @brief lcd1602_check_busy
 *
 * @return bool (SYS_OK->no busy , SYS_FAIL->busy)
 */
static bool lcd1602_check_busy(void)
{
    uint8_t i = 255;                            /* out time 255 nop */
    LCD1602_DATA_PORT = 0xFF;                   /* clear lcd1602 data port */
    lcd1602_rs_pin = 0;                         /* clear rs pin */
    lcd1602_rw_pin = 1;                         /* set rw pin */
    lcd1602_en_pin = 1;                         /* set en pin */
    while ((i--) && (LCD1602_DATA_PORT & 0x80)) /* wait busy */
        ;
    lcd1602_en_pin = 0; /* clear en pin */

    return SYS_OK;
}

/**
 * @brief lcd1602_write_to_device
 *
 * @param wr_data write data
 * @param data_type (0-cmd , 1-data)
 */
static void lcd1602_write_to_device(uint8_t wr_data, bool data_type)
{
    if (lcd1602_check_busy() != SYS_OK) /* check busy */
    {
    }
    else
    {
        LCD1602_DATA_PORT = wr_data; /* set data to port */
        lcd1602_rs_pin = data_type;  /* set rs to cmd|data */
        lcd1602_rw_pin = 0;          /* clear rw pin */
        lcd1602_en_pin = 1;          /* set en pin */
        lcd1602_en_pin = 0;          /* clear en pin */
    }
}

/**
 * @brief lcd1602_read_byte_from_device
 *
 * @return uint8_t
 */
static uint8_t lcd1602_read_byte_from_device(void)
{
    uint8_t read_data = 0x00;
    if (lcd1602_check_busy() != SYS_OK) /* check busy */
    {
    }
    else
    {
        lcd1602_rs_pin = 1;            /* set rs */
        lcd1602_rw_pin = 1;            /* clear rw pin */
        lcd1602_en_pin = 1;            /* set en pin */
        read_data = LCD1602_DATA_PORT; /* get data */
        lcd1602_en_pin = 0;            /* clear en pin */
    }
    return read_data;
}

/**
 * @brief lcd1602_set_position
 *
 * @param x [0-15]
 * @param y [0-1]
 */
static void lcd1602_set_position(uint8_t x, uint8_t y)
{
    if (0 == y)
        lcd1602_write_to_device((0x80 | x), 0);
    if (1 == y)
        lcd1602_write_to_device((0xC0 | x), 0);
}

/**
 * @brief lcd1602_init
 *
 */
void lcd1602_init(void)
{
    /* lcd1602 init start */
    lcd1602_write_to_device(0x38, 0);
    delay_ms(10);
    lcd1602_write_to_device(0x38, 0);
    delay_ms(10);
    lcd1602_write_to_device(0x38, 0);
    delay_ms(10);
    lcd1602_write_to_device(0x38, 0);
    lcd1602_write_to_device(0x08, 0);
    lcd1602_write_to_device(0x01, 0);
    lcd1602_write_to_device(0x06, 0);
    lcd1602_write_to_device(0x0C, 0);
    /* lcd1602 init end */
}

/**
 * @brief lcd1602_clear
 *
 */
void lcd1602_clear(void)
{
    lcd1602_write_to_device(0x01, 0);
}

/**
 * @brief lcd1602_display_char
 *
 * @param x [0-15]
 * @param y [0-1]
 * @param dis_char
 */
void lcd1602_display_char(uint8_t x, uint8_t y, uint8_t dis_char)
{
    lcd1602_set_position(x, y);           /* set position */
    lcd1602_write_to_device(dis_char, 1); /* write data */
}

/**
 * @brief lcd1602_display_str
 *
 * @param x [0-15]
 * @param y [0-1]
 * @param *dis_str
 */
void lcd1602_display_str(uint8_t x, uint8_t y, uint8_t *dis_str)
{
    lcd1602_set_position(x, y); /* set position */
    while (*dis_str != '\0')
    {
        lcd1602_write_to_device(*dis_str, 1); /* write data */
        dis_str++;
    }
}

/**
 * @brief lcd1602_display_one_num
 *
 * @param x [0-15]
 * @param y [0-1]
 * @param num [0-9]
 */
void lcd1602_display_one_num(uint8_t x, uint8_t y, uint8_t num)
{
    if ((('0' + num) <= '9') && (('0' + num) >= '0'))
    {
        lcd1602_set_position(x, y);            /* set position */
        lcd1602_write_to_device('0' + num, 1); /* write data */
    }
}
